
#include "WinContexts.h"

     WinContexts :: WinContexts( void )
     {
        reset();
     }

// ----------------------------------------------------------------------------------------------------

     WinContexts :: WinContexts( HWND windowHandle )
     {
        reset();
        initRendCtx( windowHandle );
     }

// ----------------------------------------------------------------------------------------------------

     void WinContexts :: reset( void )
     {
        winHand = NULL;
        devCtx  = NULL;
        renCtx  = NULL;
        state   = 1;
     }

// ----------------------------------------------------------------------------------------------------

     void WinContexts :: initPFD( void )
     {
         pixFmtDescr.nSize            = sizeof(PIXELFORMATDESCRIPTOR); // size of this pfd
         pixFmtDescr.nVersion         = 1;                             // version number
         pixFmtDescr.dwFlags          = PFD_DRAW_TO_WINDOW |           // support window
                                        PFD_SUPPORT_OPENGL |           // support OpenGL
                                        PFD_DOUBLEBUFFER;              // double buffered
         pixFmtDescr.iPixelType       = PFD_TYPE_RGBA;                 // RGBA type
         pixFmtDescr.cColorBits       = 24;                            // 24-bit color depth
         pixFmtDescr.cRedBits         = 0;
         pixFmtDescr.cRedShift        = 0;
         pixFmtDescr.cGreenBits       = 0;
         pixFmtDescr.cGreenShift      = 0;
         pixFmtDescr.cBlueBits        = 0;
         pixFmtDescr.cBlueShift       = 0;
         pixFmtDescr.cAlphaBits       = 0;                            // no alpha buffer
         pixFmtDescr.cAlphaShift      = 0;                            // shift bit ignored
         pixFmtDescr.cAccumBits       = 0;                            // no accumulation buffer
         pixFmtDescr.cAccumRedBits    = 0;
         pixFmtDescr.cAccumGreenBits  = 0;
         pixFmtDescr.cAccumBlueBits   = 0;
         pixFmtDescr.cAccumAlphaBits  = 0;                            // accum bits ignored
         pixFmtDescr.cDepthBits       = 32;                           // 32-bit z-buffer
         pixFmtDescr.cStencilBits     = 0;                            // no stencil buffer
         pixFmtDescr.cAuxBuffers      = 0;                            // no auxiliary buffer
         pixFmtDescr.iLayerType       = PFD_MAIN_PLANE;               // main layer
         pixFmtDescr.bReserved        = 0;                            // reserved
         pixFmtDescr.dwLayerMask      = 0;
         pixFmtDescr.dwVisibleMask    = 0;
         pixFmtDescr.dwDamageMask     = 0;                            // layer masks ignored
     }

// ----------------------------------------------------------------------------------------------------

     void WinContexts :: initRendCtx( HWND windowHandle )
     {
        deleteCtx();

        short failure = 0 , success = 1;

        try
        {
           if( !good() ) throw( failure );

           winHand = windowHandle;
           initPFD();               // initialize pixel format descriptor

             devCtx = GetDC( winHand );
             if( devCtx == NULL ) throw( failure ); // Cannot get device context of the window
             int PixelFormat;
             PixelFormat = ChoosePixelFormat( devCtx , &pixFmtDescr );
             if( !PixelFormat ) throw( failure );  // Cannot match pixel format to the device context
             if( !SetPixelFormat( devCtx , PixelFormat , &pixFmtDescr ) ) throw( failure );
                                                   // Cannot set pixel format to the device context
             renCtx = wglCreateContext( devCtx );
             if( renCtx == NULL ) throw( failure ); // Cannot create rendering context

             throw( success );
        }
        catch( short exc )
        {
             state = exc;
        }
        catch( ... ) // C++ exception was thrown
        {
             state = 0;
        }
     }

// ----------------------------------------------------------------------------------------------------

     void WinContexts :: deleteCtx( void )
     {
        short failure = 0 , success = 1;
        try
        {
               if( renCtx != NULL )
               {
                     if(!wglMakeCurrent( NULL , NULL )) throw( failure );
                     if(!wglDeleteContext( renCtx ))    throw( failure );
                     if(!ReleaseDC( winHand , devCtx )) throw( failure );
               }
               else
               {
                      if( devCtx != NULL )
                      {
                           if(!ReleaseDC( winHand , devCtx )) throw( failure );
                      }
               }

           throw( success );
        }
        catch( short exc )
        {
                 if( exc ) reset(); // resets if deletion went OK
        }
        catch( ... ) // C++ exception was thrown
        {
                 state = 0;
        }
     }

// ----------------------------------------------------------------------------------------------------

     short WinContexts :: good( void )
     {
        return state;
     }

// ----------------------------------------------------------------------------------------------------

     void WinContexts :: SwpBuffers( void )
     {
        SwapBuffers( devCtx );
     }

// ----------------------------------------------------------------------------------------------------

     void WinContexts :: MakeCurrent( const short flag )
     {
        if( flag )
        {
            if( !wglMakeCurrent( devCtx , renCtx ) ) state = 0; // Cannot make current rendering context
        }
        else
        {
            if( !wglMakeCurrent( NULL , NULL ) )     state = 0;
        }
     }

// ----------------------------------------------------------------------------------------------------

     WinContexts :: ~WinContexts( void )
     {
        deleteCtx();
     }

// ----------------------------------------------------------------------------------------------------
// Non-member often used functions definitions --------------------------------------------------------

short SetAndRegisterWndClass( WNDCLASSEX * WClass , const char * WClassName , WNDPROC WProcedure )
{
      WClass->cbSize        = sizeof(WNDCLASSEX);
      WClass->style         = CS_OWNDC;
      WClass->lpfnWndProc   = WProcedure;
      WClass->cbClsExtra    = 0;
      WClass->cbWndExtra    = 0;
      WClass->hInstance     = 0;
      WClass->hIcon         = LoadIcon( NULL , IDI_APPLICATION );
      WClass->hCursor       = LoadCursor( NULL , IDC_ARROW );
      WClass->hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
      WClass->lpszMenuName  = NULL;
      WClass->lpszClassName = WClassName;
      WClass->hIconSm       = LoadIcon( NULL , IDI_APPLICATION );


      if( !RegisterClassEx( WClass ) )
      {
         MessageBox( NULL , "Cannot Register Window Class." , "Error !" , MB_OK );
         return 0;
      }
      
      return 1;
}
